; floating point to ASCII code
; author:  R. Detmer
; revised:  4/98

.386
.MODEL FLAT

PUBLIC ftoaproc

C3 EQU 0100000000000000b
C2 EQU 0000010000000000b
C0 EQU 0000000100000000b

.DATA
value     REAL4  ?
ten       REAL4  10.0
one       REAL4  1.0
round     REAL4  0.000005
digit     WORD   ?
exponent  WORD   ?
controlWd WORD   ?
byteTen   BYTE   10

.CODE
ftoaproc  PROC NEAR32  ; convert floating point number to ASCII string 
; Parameters passed on the stack:
;   (1) 32-bit floating point value
;   (2) address of ASCII destination string
; ASCII string with format [blank/-]d.dddddE[+/-]dd is generated.
; (The string is always 12 characters long.)
          push ebp              ; establish stack frame
          mov  ebp, esp
          push eax              ; save registers
          push ebx
          push ecx
          push edi

          fstcw controlWd       ; get control word
          push controlWd        ; save control word
          or   controlWd, 0000110000000000b
          fldcw controlWd       ; set control to chop
          mov  edi, [ebp+8]     ; destination string address
          mov  eax, [ebp+12]    ; value to convert
          mov  exponent, 0      ; exponent := 0
          mov  value, eax       ; value to ST via memory
          fld  value
          ftst                  ; value >= 0?
          fstsw  ax             ; status word to AX
          and  ax, C0           ; check C0
          jnz  elseNeg          ; skip if set (value negative)
          mov  BYTE PTR [edi], ' '  ; blank for positive
          jmp  endifNeg
elseNeg:  mov  BYTE PTR [edi], '-'  ; minus for negative
          fchs                  ; make number positive
endifNeg:
          inc  edi              ; point at next destination byte

          mov  exponent, 0      ; exponent := 0
          ftst                  ; value = 0?
          fstsw ax              ; status word to AX
          and  ax, C3           ; check C3
          jne  endifZero        ; skip if zero
          fcom ten              ; value > 10?
          fstsw ax              ; status word to AX
          and  ax, C3 or C2 or C0   ; check for all C3=C2=C0=0
          jnz  elseLess         ; skip if value not > 10
untilLess:
          fdiv ten              ; value := value/10
          inc  exponent         ; add 1 to exponent
          fcom ten              ; value < 10
          fstsw ax              ; status word to AX
          and  ax, C0           ; check C0
          jnz  untilLess        ; continue until value < 10
          jmp  endifBigger      ; exit if
elseLess:
whileLess:
          fcom one              ; value < 1
          fstsw ax              ; status word to AX
          and  ax, C0           ; check C0
          jz   endwhileLess     ; exit if not less
          fmul ten              ; value := 10*value
          dec  exponent         ; subtract 1 from exponent
          jmp  whileLess        ; continue while value < 1
endwhileLess:
endifBigger:
endifZero:

          fadd round            ; add rounding value
          fcom ten              ; value > 10?
          fstsw ax              ; status word to AX
          and  ax, C3 or C2 or C0  ; C3=C2=C0=0? (value > 10?)
          jnz  endifOver        ; skip if not
          fdiv ten              ; value := value/10
          inc  exponent         ; add 1 to exponent
endifOver:

; at this point 1.0 <= value < 10.0
          fist digit            ; store integer part
          mov  bx, digit        ; copy integer to BX
          or   bx, 30h          ; convert digit to character
          mov  BYTE PTR [edi], bl  ; store character in destination
          inc  edi              ; point at next destination byte
          mov  BYTE PTR [edi], '.'     ; decimal point
          inc  edi              ; point at next destination byte
          
          mov  ecx, 5           ; count of remaining digits
forDigit: fisub digit           ; subtract integer part
          fmul ten              ; multiply by 10
          fist digit            ; store integer part
          mov  bx, digit        ; copy integer to BX
          or   bx, 30h          ; convert digit to character
          mov  BYTE PTR [edi], bl  ; store character in destination
          inc  edi              ; point at next destination byte
          loop forDigit         ; repeat 5 times

          mov  BYTE PTR [edi], 'E'  ; exponent indicator
          inc  edi              ; point at next destination byte
          mov  ax, exponent     ; get exponent
          cmp  ax, 0            ; exponent >= 0 ?
          jnge NegExp
          mov  BYTE PTR [edi], '+'  ; non-negative exponent
          jmp  endifNegExp
NegExp:   mov  BYTE PTR [edi], '-'  ; negative exponent
          neg  ax               ; change exponent to positive
endifNegExp:
          inc  edi              ; point at next destination byte

          div  byteTen          ; convert exponent to 2 digits
          or   ax, 3030h        ; convert both digits to ASCII
          mov  BYTE PTR [edi+1], ah  ; store characters in destination
          mov  BYTE PTR [edi], al

          pop  controlWd        ; restore control word
          fldcw controlWd
          pop  edi              ; restore registers
          pop  ecx
          pop  ebx
          pop  eax
          pop  ebp
          ret  8
ftoaproc  ENDP
          END

